#region References

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using SpoolFileLibrary.Reader.Winspool;

#endregion

namespace SpoolFileLibrary.Reader.Pcl {
    internal class PCLXLSpoolFile : ISpoolFile {
        private readonly IList<IPage> pages;
        private int copies;

        public PCLXLSpoolFile(Stream stream) {
            if(stream == null) {
                throw new ArgumentNullException("stream");
            }
            stream.Seek(0, SeekOrigin.Begin);
            this.pages = new List<IPage>();
            var streamReader = new StreamReader(stream, Encoding.UTF8, true);
            if(!this.ParseSpoolFileData(streamReader)) {
                throw new ParsingException("Failed to parse PCL XL spool file.");
            }
        }

        public bool SupportDevMode {
            get { return false; }
        }

        #region ISpoolFile Members

        public bool Parse() {
            return false;
        }

        public bool Parse(bool parsePages, int scaleFactor) {
            return false;
        }

        public SpoolFileFormat SpoolFileFormat {
            get { return SpoolFileFormat.RAW; }
        }

        public PrintjobLanguage PrintjobLanguage {
            get { return PrintjobLanguage.PCLXL; }
        }

        public IList<IPage> Pages {
            get { return this.pages; }
        }

        public int PageCount {
            get { return 1; }
        }

        public int Copies {
            get { return this.copies; }
        }

        public bool Color {
            get { return false; }
        }

        public int PaperLength {
            get { throw new NotImplementedException(); }
        }

        public int PaperWidth {
            get { throw new NotImplementedException(); }
        }

        public bool Landscape {
            get { throw new NotImplementedException(); }
        }
        
        public IDeviceMode DeviceMode {
            get { throw new NotImplementedException(); }
        }

        public byte[] RawData {
            get { throw new NotImplementedException(); }
        }

        #endregion

        private bool ParseSpoolFileData(StreamReader streamReader) {
            IDictionary<string, string> pjlValues = SpoolFileReader.GetPJLSectionValues(streamReader);
            List<string> pclCommands = this.GetPCLCommands(streamReader);

            if(pjlValues.ContainsKey("QTY")) {
                this.copies = int.Parse(pjlValues["QTY"]);
            } else {
                string copyPattern = @"&l[0-9]+X";
                string command = pclCommands.Find(p => Regex.Match(p, copyPattern).Success);
                this.copies = int.Parse(command.Trim('&', 'l', 'X'));
            }
            if(pjlValues.ContainsKey("PAPERLENGTH")) {
                this.copies = int.Parse(pjlValues["PAPERLENGTH"]);
            } else {
                string copyPattern = @"&l[0-9]+X";
                string command = pclCommands.Find(p => Regex.Match(p, copyPattern).Success);
                this.copies = int.Parse(command.Trim('&', 'l', 'X'));
            }
            return true;
        }

        private List<string> GetPCLCommands(StreamReader streamReader) {
            var pclCommands = new List<string>();
            streamReader.BaseStream.Seek(0, SeekOrigin.Begin);
            string pattern = @"\e[^%-].*";
            while(!streamReader.EndOfStream) {
                string line = streamReader.ReadLine();
                Match match = Regex.Match(line, pattern);
                if(match.Success) {
                    string[] commands = match.Value.Split(new[] {(char) 27}, StringSplitOptions.RemoveEmptyEntries);
                    foreach(string command in commands) {
                        string pclEntry = command.Trim((char) 0, (char) 1, (char) 3, (char) 4, (char) 6, (char) 8);
                        pclCommands.Add(pclEntry);
                    }
                }
            }
            return pclCommands;
        }
    }
}